using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml;

using Gtk;
using Mono.Cecil;
using MonoDevelop.Components.Commands;
using MonoDevelop.Core;
using MonoDevelop.Core.Gui.Dialogs;
using MonoDevelop.Projects;
using MonoDevelop.Projects.CodeGeneration;
using MonoDevelop.Projects.Parser;
using MonoDevelop.Projects.Text;
using MonoDevelop.Ide.Gui;
using MonoDevelop.Ide.Gui.Pads;
using MonoDevelop.Ide.Gui.Content;
using MonoDevelop.Ide.Tasks;

namespace MonoDevelop.SmokeyAddin
{
        internal static class Inspector {
                private static bool is_inspecting = false;
                private static DotNetProject current_project = null;
                                
                public static bool IsInspecting {
                        get { return Inspector.is_inspecting; }
                }                
                
                public static DotNetProject CurrentProject {
                        get { return Inspector.current_project; }
                }
                
                public static void BeginInspecting (CombineEntry entry)
                {
                        if (Inspector.is_inspecting) throw new InvalidOperationException (); // no parallel inspecting
                        Inspector.is_inspecting = true;
                        Thread thread = new Thread (Inspector.InspectEntry);
                        thread.IsBackground = true;
                        thread.Start (entry);
                }
                
                private static void InspectEntry (object entryObject)
                {
                        try {
                                CombineEntry entry = entryObject as CombineEntry;
                                ResultsReporter.BeginInspecting (entry.Name);
                                if (Inspector.IsSolution (entry)) {
                                        Inspector.InspectSolution (entry as Combine);
                                } else if (Inspector.IsDotNetProject (entry)) {
                                        Inspector.InspectDotNetProject (entry as DotNetProject);
                                } else {
                                        // do nothing
                                }
                        } catch (SmokeyAddinException ex) {
                                IdeApp.Services.MessageService.ShowError (ex);
                        } finally {
                                Inspector.is_inspecting = false;
                                ResultsReporter.EndInspecting ();
                        }
                }
                
                private static void InspectSolution (Combine solution)
                {
                        foreach (CombineEntry childEntry in solution.GetAllEntries (typeof (DotNetProject)))
                                Inspector.InspectDotNetProject (childEntry as DotNetProject);                        
                }
                
                private static void InspectDotNetProject (DotNetProject project)
                {
                        string builtAssembly = project.GetOutputFileName ();
                        if (File.Exists (builtAssembly)) {                                     
                                Inspector.current_project = project;
                                try {
                                        List<Violation> violations = SmokeyRunner.Inspect (builtAssembly);                                
                                        ResultsReporter.ReportViolations (violations);
                                } catch (SmokeyAddinException) {
                                        throw;
                                } catch (Exception ex) {
                                        throw new SmokeyAddinException (
                                                GettextCatalog.GetString ("Inspecting failed because of an unexpected error: {0}. Please, contact the plugin developers.", ex), ex);
                                } finally {
                                        Inspector.current_project = null;
                                }
                        }
                }
                                
            private static bool IsDotNetProject (CombineEntry entry)
                {
                        return entry.GetType ().IsAssignableFrom (typeof (DotNetProject));
                }

                private static bool IsSolution (CombineEntry entry)
                {
                        return entry.GetType ().IsAssignableFrom (typeof (Combine));                        
                }        
                
                public static bool IsInspectable (CombineEntry entry)
                {
                        return Inspector.IsDotNetProject (entry) || Inspector.IsSolution (entry);
                }
        }
}
